
#ifndef RT_RUDP_STATISTICS_H
#define RT_RUDP_STATISTICS_H

#include "RtDefines.h"
#include "RtStdCpp.h"

#define BITS_2_BYTES(x) (((x)+7)>>3)
#define RUDP_STAT_BUFFER_SIZE 4096

class CRtRudpStatistics
{
public:
	CRtRudpStatistics()
	{
		memset(this, 0, sizeof(CRtRudpStatistics));
	}

	double GetPacketLoss() const
	{
		return (m_totalBytesSent==0) ? (double)0 : ( (double)BITS_2_BYTES(m_totalBitsResent) / (double)m_totalBytesSent );
	}

	/// Verbosity level currently supports 0 (low), 1 (medium), 2 (high)
	CRtString ToString(int verbosityLevel = 0) const
	{
		char buffer[RUDP_STAT_BUFFER_SIZE] = "";
		if (verbosityLevel == 0)
		{
			snprintf( buffer, RUDP_STAT_BUFFER_SIZE-1,
				"              Total bytes sent: %" RT_LL_PREFIX "u\n"
				"          Total bytes received: %" RT_LL_PREFIX "u\n"
				"                    Packetloss: %.1f%%%%\n",
				m_totalBytesSent,
				m_totalBytesReceived,
				100.0f * GetPacketLoss() );
		}
		else if (verbosityLevel == 1)
		{
			LONGLONG currentTime = GetTickCountEx();
			double elapsedTime = (double)(currentTime - m_connectionStartTime) / 1000.0f;
			double bpsSent = (double)m_totalBytesSent / elapsedTime;
			double bpsReceived = (double)m_totalBytesReceived / elapsedTime;

			snprintf( buffer, RUDP_STAT_BUFFER_SIZE-1,
				"              Total bytes sent: %" RT_LL_PREFIX "u\n"
				"            Total bytes resent: %" RT_LL_PREFIX "u\n"
				"                  Packets sent: %" RT_LL_PREFIX "u\n"
				"                Packets resent: %" RT_LL_PREFIX "u\n"
				"       Packets waiting for ack: %" RT_LL_PREFIX "u\n"
				"           Packets TTL expired: %" RT_LL_PREFIX "u\n"
				"                    Packetloss: %.1f%%%%\n"
				"          Total bytes received: %" RT_LL_PREFIX "u\n"
				"              Packets received: %" RT_LL_PREFIX "u\n"
				"                  CurBandwidth: %.1f KBytes per second\n"
				"                  MaxBandwidth: %.1f KBytes per second\n"
				"                  MinBandwidth: %.1f KBytes per second\n"
				"                  Sent average: %.1f KBytes per second\n"
				"              Received average: %.1f KBytes per second\n",
				m_totalBytesSent,
				BITS_2_BYTES(m_totalBitsResent),
				m_packetsSent,
				m_packetsResent,
				m_packetsOnResendQueue,
				m_dropPacketsSent,
				100.0f * GetPacketLoss(),
				m_totalBytesReceived,
				m_packetsReceived + m_duplicatePacketsReceived + m_dropPacketsReceived,
				(double)BITS_2_BYTES((DWORD)m_curBandwidth) / 1024.0,
				(double)BITS_2_BYTES((DWORD)m_maxBandwidth) / 1024.0,
				(double)BITS_2_BYTES((DWORD)m_minBandwidth) / 1024.0,
				bpsSent / 1024.0,
				bpsReceived / 1024.0);
		}
		else
		{
			LONGLONG currentTime = GetTickCountEx();
			double elapsedTime = (double)(currentTime - m_connectionStartTime) / 1000.0f;
			double bpsSent = (double)m_totalBytesSent / elapsedTime;
			double bpsReceived = (double)m_totalBytesReceived / elapsedTime;

			snprintf( buffer, RUDP_STAT_BUFFER_SIZE-1,
				"              Total bytes sent: %" RT_LL_PREFIX "u\n"
				"            Total bytes resent: %" RT_LL_PREFIX "u\n"
				"                 Packages sent: %" RT_LL_PREFIX "u\n"
				"                  Packets sent: %" RT_LL_PREFIX "u\n"
				"                Packets resent: %" RT_LL_PREFIX "u\n"
				"       Packets waiting for ack: %" RT_LL_PREFIX "u\n"
				"       Packets data bytes sent: %" RT_LL_PREFIX "u\n"
				"      Packets total bytes sent: %" RT_LL_PREFIX "u\n"
				"       Number of packets split: %" RT_LL_PREFIX "u\n"
				"     Number of packets unsplit: %" RT_LL_PREFIX "u\n"
				"       Packet splits performed: %" RT_LL_PREFIX "u\n"
				"           Packets TTL expired: %" RT_LL_PREFIX "u\n"
				"                    Packetloss: %.1f%%%%\n"
				"          Total bytes received: %" RT_LL_PREFIX "u\n"
				"             Packages received: %" RT_LL_PREFIX "u\n"
				"              Packets received: Total:%" RT_LL_PREFIX "u Valid:%" RT_LL_PREFIX "u Dupl:%" RT_LL_PREFIX "u Drop:%" RT_LL_PREFIX "u\n"
				"Sequenced packets out of order: %" RT_LL_PREFIX "u\n"
				"    Sequenced packets in order: %" RT_LL_PREFIX "u\n"
				"  Ordered packets out of order: %" RT_LL_PREFIX "u\n"
				"      Ordered packets in order: %" RT_LL_PREFIX "u\n"
				"   Packets waiting for reorder: %" RT_LL_PREFIX "u\n"
				" Splits waiting for reassembly: %" RT_LL_PREFIX "u\n"
				"               Elapsed seconds: %.1f\n"
				"                  CurBandwidth: %.1f KBytes per second\n"
				"                  MaxBandwidth: %.1f KBytes per second\n"
				"                  MinBandwidth: %.1f KBytes per second\n"
				"                  Sent average: %.1f KBytes per second\n"
				"              Received average: %.1f KBytes per second\n"
				"                  PacketNumber: %u\n"
				"      ReceivedPacketsBaseIndex: %u\n"
				"           ReliablePacketsSent: %" RT_LL_PREFIX "u\n"
				"          ReliablePacketsAcked: %" RT_LL_PREFIX "u\n",
				m_totalBytesSent,
				BITS_2_BYTES(m_totalBitsResent),
				m_packagesSent,
				m_packetsSent,
				m_packetsResent,
				m_packetsOnResendQueue,
				BITS_2_BYTES(m_packetDataBitsSent),
				BITS_2_BYTES(m_packetTotalBitsSent),
				m_numberOfSplitPacket,
				m_numberOfUnsplitPacket,
				m_totalSplits,
				m_dropPacketsSent,
				100.0f * GetPacketLoss(),
				m_totalBytesReceived,
				m_packagesReceived,
				m_packetsReceived + m_duplicatePacketsReceived + m_dropPacketsReceived, m_packetsReceived, m_duplicatePacketsReceived, m_dropPacketsReceived, 
				m_sequencedPacketsOutOfOrder,
				m_sequencedPacketsInOrder,
				m_orderedPacketsOutOfOrder,
				m_orderedPacketsInOrder,
				m_packetsWaitingForReorder,
				m_splitsWaitingForReassembly,
				elapsedTime,
				(double)BITS_2_BYTES((DWORD)m_curBandwidth) / 1024.0,
				(double)BITS_2_BYTES((DWORD)m_maxBandwidth) / 1024.0,
				(double)BITS_2_BYTES((DWORD)m_minBandwidth) / 1024.0,
				bpsSent / 1024.0,
				bpsReceived / 1024.0,
				m_messageNumber,
				m_receivedPacketsBaseIndex,
				m_reliablePacketsSent,
				m_reliablePacketsAcked);
		}

		return CRtString(buffer);
	}

public:
	LONGLONG m_connectionStartTime;

	// Send
	LONGLONG m_totalBytesSent;
	LONGLONG m_packagesSent;
	LONGLONG m_packetsSent;
	LONGLONG m_packetDataBitsSent;
	LONGLONG m_packetTotalBitsSent;
	WORD m_messageNumber;

	// Receive
	LONGLONG m_totalBytesReceived;
	LONGLONG m_packagesReceived;
	LONGLONG m_packetsReceived;
	LONGLONG m_duplicatePacketsReceived;
	WORD m_receivedPacketsBaseIndex;

	// Reliable Packet
	LONGLONG m_reliablePacketsSent;
	LONGLONG m_reliablePacketsAcked;
	LONGLONG m_packetsOnResendQueue;
	LONGLONG m_packetsResent;
	LONGLONG m_totalBitsResent;

	// Split Data
	LONGLONG m_numberOfSplitPacket;
	LONGLONG m_numberOfUnsplitPacket;
	LONGLONG m_totalSplits;
	LONGLONG m_splitsWaitingForReassembly;

	// Sequenced & Ordered Packet
	LONGLONG m_sequencedPacketsOutOfOrder;
	LONGLONG m_sequencedPacketsInOrder;
	LONGLONG m_orderedPacketsOutOfOrder;
	LONGLONG m_orderedPacketsInOrder;
	LONGLONG m_packetsWaitingForReorder;

	// Bandwidth
	double m_curBandwidth; // in bits per second
	double m_maxBandwidth; // in bits per second
	double m_minBandwidth; // in bits per second

	// Drop Packet PDU
	LONGLONG m_dropPacketsSent;
	LONGLONG m_dropPacketsReceived;
};

#endif // RT_RUDP_STATISTICS_H

